/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package servicios;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.jws.WebService;
import logica.entidades.Barco;
import logica.entidades.Barremina;
import logica.entidades.Coordenada;
import logica.entidades.Islas;
import logica.entidades.Minador;
import logica.entidades.Nivel;
import logica.entidades.Partida;
import logica.entidades.Partidas;
import logica.entidades.Puertos;
import persistencia.FachadaPersistencia;

/**
 *
 * @author user
 */
@WebService
public class Fachada {  
    
    private static Fachada INSTANCIA = null;
    public final Lock monitor = new ReentrantLock();
    private static Partidas partidas;
    
    //tOdo: VERIFICAR ESTO
    public Fachada() {

    }
    
    private synchronized static void crearInstancia(){
        if(INSTANCIA == null) {
            INSTANCIA = new Fachada();
            partidas = new Partidas();
        }
    }
    
    public static Fachada obtenerInstancia() {
        crearInstancia();
        return INSTANCIA;
    }  
    
    //Retorna un String parseado con el IdJugador y turno
    public String JugarPartida(String nombre,int idNivel)  
    {
         try { 
            if (monitor.tryLock(1, TimeUnit.SECONDS)) {
                    try {
                        obtenerInstancia();
                        int result = 0;
                        String resultado=  "";
                        Partida partida = partidas.GetPartidaAbierta();
                        if(partida == null)
                        {
                            Partida partidaIniciar = new Partida();
                            if(partidaIniciar.getJugadores().CantidadJugadores() == 0)
                            {
                                //CREAR LA PARTIDA JUGADOR 1
                                String rol = "Anfitrion";
                                FachadaPersistencia fachadaPers = new FachadaPersistencia(); 
                                int idJugador = fachadaPers.ObtenerUltimoIdJugador() + 1;
                                int idBarco = fachadaPers.ObtenerUltimoIdBarco() + 1;
                                Nivel nivel = fachadaPers.GetNivel(idNivel);    
                                result = partidaIniciar.IniciarPartida(nombre, rol, nivel,idJugador,idBarco);
                                if(partidaIniciar.GetTurnos().GetTurnoActual().GetIdTurno() == result)
                                {
                                    resultado = result + "," + 1 + "," + "M" ;
                                }
                                else
                                {
                                    resultado = result + "," + 0 + "," + "M";
                                }
                            }
                            partidas.AgregarPartida(partidaIniciar);
                        }
                        else
                        {
                            if(partida.getJugadores().CantidadJugadores() < 2)
                            {
                                    //UNIRSE A PARTIDA
                                    String rol = "Visitante";
                                    FachadaPersistencia fachadaPers = new FachadaPersistencia(); 
                                    int idJugador = fachadaPers.ObtenerUltimoIdJugador() + 1;
                                    int idBarco = fachadaPers.ObtenerUltimoIdBarco() + 1;
                                    Nivel nivel = fachadaPers.GetNivel(idNivel);   
                                    result = partida.UnircePartida(nombre, rol);
                                    if(partida.GetTurnos().GetTurnoActual().GetIdTurno() == result)
                                    {
                                        resultado = result + "," + 1 + "," + "B";
                                    }
                                    else
                                    {
                                        resultado = result + "," + 0 + "," + "B";
                                    }
                                    //Trayectoria para el barco 
                                    int numeroTray = (int) (Math.random()* 3 + 1);
                                    ArrayList<Coordenada> trayectoria = fachadaPers.GetTrayectoria(numeroTray);
                                    partida.UnirJugadorSistema("Sistema",nivel.GetTiempoSalidaCrucero(), trayectoria);
                            }
                            else
                            {
                                resultado = -1 + "," + 0; 
                            }
                        }
                        return resultado;
                    } catch (SQLException ex) {
                     Logger.getLogger(Fachada.class.getName()).log(Level.SEVERE, null, ex);
                 } finally {
                                  monitor.unlock();
                                }
                        }
                     } catch (InterruptedException ex) {
            Logger.getLogger(Fachada.class.getName()).log(Level.SEVERE, null, ex);
        }
       return null;
    }
    
    public void MoverBarco(int idJugador,int CoordX,int CoordY)
    {
        try { 
            if (monitor.tryLock(1, TimeUnit.SECONDS)) {
                    try {
                        Partida partida = partidas.GetPartidaJuego();
                        if(partida != null)
                        {
                            Coordenada coord = new Coordenada(CoordX, CoordY);
                            partida.MoverBarcoPartida(idJugador, coord);
                            partida.ExisteColisionMinaSuperficie(idJugador);
                        }
                        } finally {
                                  monitor.unlock();
                                }
                        }
                     } catch (InterruptedException ex) {
            Logger.getLogger(Fachada.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    public ArrayList<String> ActualizacionDePartida(int idJugador)
    {
        try { 
            if (monitor.tryLock(1, TimeUnit.SECONDS)) {
                    try {
                        ArrayList<String> result = new ArrayList<String>();
                        obtenerInstancia();
                        Partida partida = partidas.GetPartidaJuego();
                        if(partida != null)
                        {
                            result = partida.ActualizacionDePartida(idJugador);
                        }
                        return result;
                        } finally {
                                  monitor.unlock();
                                }
                        }
                     } catch (InterruptedException ex) {
            Logger.getLogger(Fachada.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }
    public ArrayList<String> GetEstaticos()
    {
        FachadaPersistencia fachadaPers = new FachadaPersistencia();
        Islas islas = fachadaPers.GetIslas();
        Puertos puertos = fachadaPers.GetPuertos();
        ArrayList<String> result = new ArrayList<String>();
        obtenerInstancia();
        Partida partida = partidas.GetPartidaJuego();

        if(partida != null)
        {
            result = partida.GetEstaticos(islas, puertos);
        }
        else
        {
            partida = partidas.GetPartidaAbierta();
            result = partida.GetEstaticos(islas, puertos);
        }

        return result;
    }
    public boolean ExistePartidaAbierta()
    {
        try { 
            if (monitor.tryLock(1, TimeUnit.SECONDS)) {
                    try {
                        obtenerInstancia();
                        Partida partida = partidas.GetPartidaAbierta();
                        if(partida != null)
                        {
                            return true;
                        }
                        else
                        {
                            return false;
                        }
                        } finally {
                                  monitor.unlock();
                                }
                        }
                     } catch (InterruptedException ex) {
            Logger.getLogger(Fachada.class.getName()).log(Level.SEVERE, null, ex);
        }
        return false;
    }
    public boolean ExistePartidaJuego()
    {
        try { 
            if (monitor.tryLock(1, TimeUnit.SECONDS)) {
                    try {
                        obtenerInstancia();
                        Partida partida = partidas.GetPartidaJuego();
                        if(partida != null)
                        {
                            return true;
                        }
                        else
                        {
                            return false;
                        }
                        } finally {
                                  monitor.unlock();
                                }
                        }
                     } catch (InterruptedException ex) {
            Logger.getLogger(Fachada.class.getName()).log(Level.SEVERE, null, ex);
        }
        return false;
    }
    public void PasarTurno()
    {
         try { 
            if (monitor.tryLock(1, TimeUnit.SECONDS)) {
                    try {
                        obtenerInstancia();
                        Partida partida = partidas.GetPartidaJuego();
                        if(partida != null)
                        {
                            partida.PasarTurno();
                        }
        } finally {
                                  monitor.unlock();
                                }
                        }
                     } catch (InterruptedException ex) {
            Logger.getLogger(Fachada.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
        
    public boolean LanzarMinaSuperficie(int idJugador) {
        try { 
            if (monitor.tryLock(1, TimeUnit.SECONDS)) {
                    try {
                        Partida partida = partidas.GetPartidaJuego();
                        boolean result = false;
                        if(partida != null)
                        {
                            Barco barco = partida.getJugadores().ObtenerJugador(idJugador).GetBarco();
                            if(barco instanceof Minador)
                            {
                                Minador barcoMinador = (Minador)barco;
                                result = barcoMinador.lanzarMinaSuperficie();   
                                if(result)
                                {
                                     partida.IncrementarAccionesTurno();
                                }
                                return result;
                            }                       
                        }
                    } finally {
                         monitor.unlock();
                   }
            }
        } catch (InterruptedException ex) {
            Logger.getLogger(Fachada.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        return false;
    }
    public boolean LanzarMinaProfundidad(int idJugador) {
        try { 
            if (monitor.tryLock(1, TimeUnit.SECONDS)) {
                    try {
                        Partida partida = partidas.GetPartidaJuego();
                        boolean result = false;
                        if(partida != null)
                        {
                            Barco barco = partida.getJugadores().ObtenerJugador(idJugador).GetBarco();
                            if(barco instanceof Minador)
                            {
                                Minador barcoMinador = (Minador)barco;
                                result = barcoMinador.lanzarMinaProfundidad();   
                                if(result)
                                {
                                    partida.IncrementarAccionesTurno();
                                }
                            }
                        }
                    } finally {
                         monitor.unlock();
                   }
            }
        } catch (InterruptedException ex) {
            Logger.getLogger(Fachada.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        return false;
    }

    public ArrayList<String> lanzarProyectil(int idJugador) {
        ArrayList<String> trayectoria = new ArrayList<String>();
        try { 
            if (monitor.tryLock(1, TimeUnit.SECONDS)) {
                    try {
                        Partida partida = partidas.GetPartidaJuego();
                        if(partida != null)
                        {
                            Barco barco = partida.getJugadores().ObtenerJugador(idJugador).GetBarco();
                            int numeroBarco;
                            if(barco instanceof  Minador)
                            {
                                numeroBarco = 0;
                            } else {
                                numeroBarco = 1;
                            }
                            trayectoria = barco.lanzarProyectil(numeroBarco);
                            partida.IncrementarAccionesTurno();
                            Coordenada coordImpacto = barco.determinarPuntoImpactoProyectil(numeroBarco);
                            partida.ExisteColisionProyectil(idJugador, coordImpacto);
                            partida.EliminarMinaSuperficie(coordImpacto);
                        }
                    } finally {
                         monitor.unlock();
                   }
            }
        } catch (InterruptedException ex) {
            Logger.getLogger(Fachada.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        return trayectoria;
    }
    
    public boolean tengoProyectiles(int idJugador) {
    try { 
            if (monitor.tryLock(1, TimeUnit.SECONDS)) {
                    try {
                        Partida partida = partidas.GetPartidaJuego();
                        if(partida != null)
                        {
                            Barco barco = partida.getJugadores().ObtenerJugador(idJugador).GetBarco();
                            return barco.tengoProyectiles();
                        }
                    } finally {
                         monitor.unlock();
                   }
            }
        } catch (InterruptedException ex) {
            Logger.getLogger(Fachada.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        return false;
    }
    
    public void guardarPartida(){
        try { 
            if (monitor.tryLock(1, TimeUnit.SECONDS)) {
                    try {
                        obtenerInstancia();
                        Partida partida = partidas.GetPartidaJuego();
                        if(partida != null){
                           FachadaPersistencia fachadaPersistencia = new FachadaPersistencia();
                           fachadaPersistencia.GuardarPartida(partida);
                        }
                        } finally {
                                  monitor.unlock();
                                }
                        }
                     } catch (InterruptedException ex) {
            Logger.getLogger(Fachada.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    //Carga de profundidad
    public boolean LanzarCargaProfundidad() {
        try { 
            if (monitor.tryLock(1, TimeUnit.SECONDS)) {
                    try {
                        boolean result = false;
                        Partida partida = partidas.GetPartidaJuego();
                        if(partida != null)
                        {                           
                            result = partida.EliminarMinaProfundidad();
                            if(result)
                            {
                                partida.IncrementarAccionesTurno();
                            }
                            return result;
                        }
                    } finally {
                         monitor.unlock();
                   }
            }
        } catch (InterruptedException ex) {
            Logger.getLogger(Fachada.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        return false;
    }
    
    public boolean tengoCargasProfundidad(int idJugador) {
        try { 
                if (monitor.tryLock(1, TimeUnit.SECONDS)) {
                        try {
                            Partida partida = partidas.GetPartidaJuego();
                            if(partida != null)
                            {
                                Barco barco = partida.getJugadores().ObtenerJugador(idJugador).GetBarco();
                                if(barco instanceof Barremina)
                                {
                                    //partida.IncrementarAccionesTurno();
                                    Barremina barcoBarremina = (Barremina)barco;
                                    return barcoBarremina.tengoCargasDeProfundidad();

                                }
                            }
                        } finally {
                             monitor.unlock();
                       }
                }
            } catch (InterruptedException ex) {
                Logger.getLogger(Fachada.class.getName()).log(Level.SEVERE, null, ex);
            }
        
        return false;
    }
    
    public void finalizarPartida(){
        try { 
            if (monitor.tryLock(1, TimeUnit.SECONDS)) {
                    try {
                        obtenerInstancia();
                        Partida partida = partidas.GetPartidaJuego();
                        if(partida != null){
                           partida.FinalizarPartida();
                        }
                        } finally {
                                  monitor.unlock();
                                }
                        }
                     } catch (InterruptedException ex) {
            Logger.getLogger(Fachada.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
}
